/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package control;

import entidad.Medicion;
import java.util.ArrayList;
import java.util.Random;
import control.CRUDDatos;

/**
 *
 * @author Camilo
 */
public class TratamientoDatos {

    /**
     * @param args the command line arguments
     *//*
     * public static void main(String[] args) { ArrayList<Medicion> nuevo = new
     * ArrayList(); Medicion a = new Medicion(); Medicion b = new Medicion();
     * Medicion c = new Medicion(); Medicion d = new Medicion(); Medicion e =
     * new Medicion(); Medicion f = new Medicion(); Medicion g = new Medicion();
     *
     * a.setPluviosidad(1.0); a.setPresion(1.0); a.setTemperatura(1.0);
     * b.setPluviosidad(1.0); b.setPresion(1.0); b.setTemperatura(1.0);
     * c.setPluviosidad(1.0); c.setPresion(1.0); c.setTemperatura(1.0);
     * d.setPluviosidad(2.0); d.setPresion(2.0); d.setTemperatura(2.0);
     * e.setPluviosidad(3.0); e.setPresion(3.0); e.setTemperatura(3.0);
     * f.setPluviosidad(4.0); f.setPresion(4.0); f.setTemperatura(4.0);
     * g.setPluviosidad(5.0); g.setPresion(5.0); g.setTemperatura(5.0);
     *
     * nuevo.add(a); nuevo.add(b); nuevo.add(c); nuevo.add(d); nuevo.add(e);
     * nuevo.add(f); nuevo.add(g);
     *
     * TratamientoDatos test = new TratamientoDatos(); Medicion testing =
     * test.mediana(nuevo); Medicion testing1 = test.moda(nuevo);
     * System.out.println("media"+testing.getPluviosidad() + " " +
     * testing.getPresion() + "+" + testing.getTemperatura());
     * System.out.println("moda"+testing1.getPluviosidad() + " " +
     * testing1.getPresion() + "+" + testing1.getTemperatura());
     *
     * }
     */

    public Medicion media() {
        CRUDDatos n = new CRUDDatos();
        ArrayList<Medicion> datos = n.consultarDatos();
        int cantidad = 0;
        double sumaTemp = 0;
        double sumaPres = 0;
        double sumaPluv = 0;

        for (Medicion m : datos) {
            sumaTemp = m.getTemperatura() + sumaTemp;
            sumaPres = m.getPresion() + sumaPres;
            sumaPluv = m.getPluviosidad() + sumaPluv;
            cantidad++;
        }

        double pluviosidad = sumaPluv / cantidad;
        double presion = sumaPres / cantidad;
        double temperatura = sumaTemp / cantidad;

        Medicion medicionPromedio = new Medicion();
        medicionPromedio.setPluviosidad(pluviosidad);
        medicionPromedio.setPresion(presion);
        medicionPromedio.setTemperatura(temperatura);
        return medicionPromedio;
    }

    public Medicion mediana() {
        CRUDDatos n = new CRUDDatos();
        ArrayList<Medicion> datos = n.consultarDatos();
        Medicion medicionMediana = new Medicion();
        double[] pluv = new double[datos.size() + 1];
        double[] pres = new double[datos.size() + 1];
        double[] temp = new double[datos.size() + 1];

        int cont = 0;
        for (Medicion m : datos) {

            pluv[cont] = m.getPluviosidad();
            pres[cont] = m.getPresion();
            temp[cont] = m.getTemperatura();

            cont++;
        }
        mergeSort(pluv, 1, cont - 1);
        mergeSort(pres, 1, cont - 1);
        mergeSort(temp, 1, cont - 1);

        /*
         * for (int aux = 1; aux <= cont - 1; aux++) {
         * System.out.println(pluv[aux]); System.out.println("");
        }
         */

        if (cont % 2 == 0) { //si la cantidad de elementos es par
            medicionMediana.setPluviosidad(pluv[(cont + 1) / 2]);
            medicionMediana.setPresion(pres[(cont + 1) / 2]);
            medicionMediana.setTemperatura(temp[(cont + 1) / 2]);
        } else { // cantidad de elementos impar
            medicionMediana.setPluviosidad(pluv[((cont / 2) + ((cont / 2) + 1)) / 2]);
            medicionMediana.setPresion(pres[((cont / 2) + ((cont / 2) + 1)) / 2]);
            medicionMediana.setTemperatura(temp[((cont / 2) + ((cont / 2) + 1)) / 2]);
        }
        return medicionMediana;
    }

    private void mergeSort(double v[], int p, int q) {


        if (p < q) {
            int k = (p + q) / 2; // punto medio del vector 
            mergeSort(v, p, k); // Ordenando la primera mitad 
            mergeSort(v, k + 1, q); // Ordenando la seguda mitad 
            combinar(v, p, k + 1, q); // uniendo las dos mitades 
        }
    }

    private void combinar(double v[], int p, int m, int q) {
        int combinado[] = new int[q - p + 1];

        int p1 = p;
        int p2 = m;
        int p3 = 0;


        while (p1 < m && p2 <= q) {
            if (v[p1] < v[p2]) {
                combinado[p3] = (int) v[p1];
                p1 = p1 + 1;
            } else {
                combinado[p3] = (int) v[p2];
                p2 = p2 + 1;
            }
            p3 = p3 + 1;
        }

        while (p1 < m) {
            combinado[p3] = (int) v[p1];
            p1 = p1 + 1;
            p3 = p3 + 1;
        }

        while (p2 <= q) {
            combinado[p3] = (int) v[p2];
            p2 = p2 + 1;
            p3 = p3 + 1;
        }


        for (int i = 0; i < q - p + 1; i++) {
            v[p + i] = combinado[i];
        }
    }

    public Medicion varianza() {
        CRUDDatos n = new CRUDDatos();
        ArrayList<Medicion> datos = n.consultarDatos();
        Medicion promedio = media();
        Medicion medicionVar = new Medicion();

        int cont = 1;
        double sumaPluv = 0;
        double sumaTemp = 0;
        double sumaPres = 0;
        for (Medicion m : datos) {

            sumaPluv = ((m.getPluviosidad() - promedio.getPluviosidad()) * (m.getPluviosidad() - promedio.getPluviosidad())) + sumaPluv;
            sumaTemp = ((m.getTemperatura() - promedio.getTemperatura()) * (m.getTemperatura() - promedio.getTemperatura())) + sumaTemp;
            sumaPres = ((m.getPresion() - promedio.getPresion()) * (m.getPresion() - promedio.getPresion())) + sumaPres;

            cont++;
        }

        medicionVar.setPluviosidad(sumaPluv / cont);
        medicionVar.setPresion(sumaPres / cont);
        medicionVar.setTemperatura(sumaTemp / cont);

        return medicionVar;
    }

    public Medicion desviacionEstandar() {
        // CRUDDatos n = new CRUDDatos();
        // ArrayList <Medicion>datos = n.consultarDatos();
        Medicion medicionDesv = new Medicion();
        Medicion medVar = varianza();
        medicionDesv.setPluviosidad(Math.sqrt(medVar.getPluviosidad()));
        medicionDesv.setPresion(Math.sqrt(medVar.getPresion()));
        medicionDesv.setTemperatura(Math.sqrt(medVar.getTemperatura()));
        return medicionDesv;
    }

    public Medicion rangoIntercuartilico() {
        CRUDDatos n = new CRUDDatos();
        ArrayList<Medicion> datos = n.consultarDatos();
        Medicion medicionRango = new Medicion();

        double[] pluv = new double[datos.size() + 1];
        double[] pres = new double[datos.size() + 1];
        double[] temp = new double[datos.size() + 1];

        int cont = 1;
        for (Medicion m : datos) {

            pluv[cont] = m.getPluviosidad();
            pres[cont] = m.getPresion();
            temp[cont] = m.getTemperatura();

            cont++;
        }

        mergeSort(pluv, 1, cont - 1); //no se sabe si es cont o cont+1 o cont -1
        mergeSort(pres, 1, cont - 1);
        mergeSort(temp, 1, cont - 1);

        double pluvq1;
        double pluvq3;
        double presq1;
        double presq3;
        double tempq1;
        double tempq3;
        double ricPres;
        double ricTemp;
        double ricPluv;

        double q1;
        double q3;
        q1 = (cont - 1) / 4;
        q3 = 3 * (cont + 1) / 4;
        if (((int) q1 - q1) != 0) {
            if ((int) q1 - q1 == 0.5) {
                pluvq3 = (pluv[(int) q3] + pluv[(int) q3 + 1]) / 2;
                pluvq1 = (pluv[(int) q1] + pluv[(int) q1 + 1]) / 2;
                tempq3 = (temp[(int) q3] + temp[(int) q3 + 1]) / 2;
                tempq1 = (temp[(int) q1] + temp[(int) q1 + 1]) / 2;
                presq3 = (pres[(int) q3] + pres[(int) q3 + 1]) / 2;
                presq1 = (pres[(int) q1] + pres[(int) q1 + 1]) / 2;
                ricPluv = pluvq3 - pluvq1;
                ricTemp = tempq3 - tempq1;
                ricPres = presq3 - presq1;
                medicionRango.setPluviosidad(ricPluv);
                medicionRango.setPresion(ricPres);
                medicionRango.setTemperatura(ricTemp);
            } else {

                pluvq3 = pluv[(int) Math.round(q3)];
                pluvq1 = pluv[(int) Math.round(q1)];
                tempq3 = temp[(int) Math.round(q3)];
                tempq1 = temp[(int) Math.round(q1)];
                presq3 = pres[(int) Math.round(q3)];
                presq1 = pres[(int) Math.round(q1)];

                ricPluv = pluvq3 - pluvq1;
                ricTemp = tempq3 - tempq1;
                ricPres = presq3 - presq1;
                medicionRango.setPluviosidad(ricPluv);
                medicionRango.setPresion(ricPres);
                medicionRango.setTemperatura(ricTemp);
            }

        } else {

            ricPluv = pluv[(int) q3] - pluv[(int) q1];
            ricTemp = temp[(int) q3] - temp[(int) q1];
            ricPres = pres[(int) q3] - pres[(int) q1];
            medicionRango.setPluviosidad(ricPluv);
            medicionRango.setPresion(ricPres);
            medicionRango.setTemperatura(ricTemp);
        }
        return medicionRango;
    }

    public Medicion moda() {
         CRUDDatos n = new CRUDDatos();
        ArrayList<Medicion> datos = n.consultarDatos();
        Medicion medicionModa = new Medicion();

        double[] pluv = new double[datos.size() + 1];
        double[] pres = new double[datos.size() + 1];
        double[] temp = new double[datos.size() + 1];
       // int cont = 1;


        medicionModa.setPluviosidad(hallarModa(pluv, 1, datos.lastIndexOf(datos)));
        medicionModa.setTemperatura(hallarModa(temp, 1, datos.lastIndexOf(datos)));
        medicionModa.setPresion(hallarModa(pres, 1, datos.lastIndexOf(datos)));
        return medicionModa;

    }

    /**
     * Metodo para hallar la moda en un vector de doubles Utilizando la tecnica
     * Divide y Venceras
     *
     * @param a
     * @param prim
     * @param ult
     * @return
     */
    public static double hallarModa(double[] a, int prim, int ult) {
        int i;
        double frec, maxfrec, moda;
        if (prim == ult) {
            return a[(int) prim];
        }
        moda = a[(int) prim];
        maxfrec = Frecuencia(a, a[(int) prim], prim, ult);
        for (i = (int) prim + 1; i <= ult; i++) {
            frec = Frecuencia(a, a[i], i, ult);
            if (frec > maxfrec) {
                maxfrec = frec;
                moda = a[i];
            }
        }

        return moda;
    }

    /**
     * Metodo para calcular el numero de veces que se repite un elemento
     * Utilizado por el metodo hallarModa
     *
     * @param a
     * @param p
     * @param prim
     * @param ult
     * @return
     */
    public static double Frecuencia(double a[], double p, double prim, double ult) {
        int i;
        double suma;
        if (prim > ult) {
            return 0;
        }
        suma = 0;
        for (i = (int) prim; i <= ult; i++) {
            if (a[i] == p) {
                suma++;
            }
        }

        return suma;

    }

    /**
     * Metodo para cargar el vector con valores int aleatorios
     *
     * @param a
     */
    public static void cargarVector(Double a[]) {
        Random r = new Random();			//Variable para el numero generado aleatoriamente
        for (int i = 0; i < a.length; i++) {		//Cargamos el vector con valores aleatorios
            a[i] = (double) (r.nextInt(100));   		//Genera y carga valores aleatorios en elVector
        }
    }

    /**
     * Metodo para imprimir el vector
     *
     * @param a
     *//*
     * public static void imprimirVector(int a[]) { System.out.println("\nEl
     * vector es:"); for (int i = 0; i < a.length; i++) { System.out.printf("%d
     * ", (a[i])); } }
     */

    public ArrayList<Medicion> regresion() {
         CRUDDatos n = new CRUDDatos();
        ArrayList<Medicion> datos = n.consultarDatos();
        int cont = 1;
        double yPluv = 0;
        double yPres = 0;
        double yTemp = 0;
        double x = 0;
        double xyPluv = 0;
        double xyTemp = 0;
        double xyPres = 0;
        double xCuad = 0;

        for (Medicion m : datos) {

            yPluv = m.getPluviosidad() + yPluv; //suma de y
            yPres = m.getPresion() + yPres; //suma de y
            yTemp = m.getTemperatura() + yTemp; // suma de y

            xyPluv = m.getPluviosidad() * m.getId() + xyPluv; //producto xy
            xyTemp = m.getTemperatura() * m.getId() + xyTemp;
            xyPres = m.getPresion() * m.getId() + xyPres;

            x = m.getId() + x; //suma de x
            xCuad = m.getId() * m.getId() + xCuad;

            cont++;
        }
        //a suma de x c suma cuadrados x d suma de y*x b suma de y
        //B = (a * d - c* b) / (-1* n *c )+ (a*a);
        // A = (b - (n*B)) / a;

        //para calcular la funcion se hallan A y B
        double Bpres = ((x * xyPres - xCuad * yPres)) / ((-1 * cont * xCuad) + (x * x));
        double Btemp = ((x * xyTemp - xCuad * yTemp)) / ((-1 * cont * xCuad) + (x * x));
        double Bpluv = ((x * xyPluv - xCuad * yPluv)) / ((-1 * cont * xCuad) + (x * x));

        double Apres = ((yPres - (cont * Bpres)) / x);
        double Apluv = ((yPluv - (cont * Bpluv)) / x);
        double Atemp = ((yTemp - (cont * Btemp)) / x);

        //genera los nuevos datos
        for (int k = 1; k <= 10; k++) {
            Medicion nueva = new Medicion();
            nueva.setPresion((Apres * cont + k) + Bpres);
            nueva.setPluviosidad((Apluv * cont + k) + Bpluv);
            nueva.setTemperatura((Atemp * cont + k) + Btemp);
            datos.add(nueva);
        }

        return datos;
    }
}